//============================================================================
// Name        : GAQCA.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <math.h>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

#include "Entity/Layer.h"
#include "Entity/Cell.h"
#include "Entity/Circuit.h"
#include "Entity/Output.h"
#include "Entity/Chromosome.h"
#include "Entity/Instance.h"
#include "Entity/Individual.h"
#include "Model/ChromosomeDecoder.h"
#include "Model/GeneticAlgorithm.h"
#include "Model/DecoderCircuitAdapter.h"
#include "Entity/RandomNumber.h"
#include "Boundary/Config.h"
#include "Boundary/InstanceLayerDefault.h"
#include "Entity/TruthTable.h"
#include "Model/CrossoverPathRepresentationOX.h"
#include "Model/CrossoverBinaryRepresentationPoint.h"
#include "Entity/GASimulation.h"
#include "Model/TetaEvaluationFunction.h"
#include "Model/FiEvaluationFunction.h"
#include "Model/InsertionHeuristic.h"
#include "Model/GuidedInsertionHeuristic.h"
#include "Model/RandomInsertionHeuristic.h"
#include "Model/MatrixPositionAndClockComparator.h"
#include "Model/RemoveLocalSearch.h"
#include "Model/RemoveInsertionLocalSearch.h"
#include "Model/RemoveTwoAndInsertOneLocalSearch.h"

#include "Boundary/LatexOutput.h"
//
//void print_test_log(std::map<std::string,Samples> results, Layer layer) {
//
//    double sum = 0;
//    std::cout <<"*************************************"<<std::endl;
//    for (std::map<std::string,Samples>::iterator it_sample = results.begin(); it_sample != results.end(); ++it_sample) {
//        std::cout << it_sample->first << ":";
//                it_sample->second.printValues();
//    }
//    std::vector<Cell*> output_cells = layer.get_list_cells_by_function(&layer,Cell::OUTPUT_CELL_FUNCTION);
//
//    for (int i = 0; i < (int)output_cells.size(); ++i) {
//        std::cout << "CLOCK " << output_cells[i]->cell_name() << ":" << output_cells[i]->cell_clock_zone() << std::endl;
//    }
//
//    std::cout <<"*************************************"<<std::endl;
//
//
//}
void print_test_log(std::map<std::string,Samples> results, Layer layer) {


    std::cout <<"*************************************"<<std::endl;
    for (std::map<std::string,Samples>::iterator it_sample = results.begin(); it_sample != results.end(); ++it_sample) {
        std::cout << it_sample->first << ":";
        it_sample->second.printValues();
    }
    std::vector<Cell*> output_cells = layer.get_list_cells_by_function(&layer,Cell::OUTPUT_CELL_FUNCTION);

    for (int i = 0; i < (int)output_cells.size(); ++i) {
        std::cout << "CLOCK " << output_cells[i]->cell_name() << ":" << output_cells[i]->cell_clock_zone() << std::endl;
    }

    std::cout <<"*************************************"<<std::endl;



}
int main(int argc,char *argv[]) {
    RandomNumber::get_instance(2);
    InstanceLayerDefault layer_default;
    Instance instance = layer_default.readInstanceWithLayerDefault("instances/2input/or_fixed_eulerian.instance");

    std::cout << instance.get_layer_default()->print_layer() << std::endl;
    EvaluationFunction * function = NULL;
    function = new FiEvaluationFunction();
    instance.set_evaluation_funcion(function);

    RandomInsertionHeuristic randon_heuristic;
    Layer guided_layer = randon_heuristic.generate_random_layer(instance);
    std::cout << guided_layer.print_layer() << std::endl;

    Individual individual;
    individual.set_layer(guided_layer);
    Circuit circuito(&guided_layer,instance.truth_table());
    std::vector<std::vector<Samples> > results = circuito.execute_circuit(instance);
    double polarization_error_best_individual = individual.calculate_polarization_error(instance,results);

    GuidedInsertionHeuristic heuristic;
    LatexOutput latex;
    for (int i = 0; i < 30; ++i) {

        Layer layer = heuristic.generate_guided_layer(instance,guided_layer,0.5);
        //        Layer layer = randon_heuristic.generate_random_layer(instance);
        circuito = Circuit(&layer,instance.truth_table());
        results = circuito.execute_circuit(instance);
        Individual individual;
        individual.set_layer(layer);
        double polarization_error_ = individual.calculate_polarization_error(instance,results);
        individual.set_traces(results);
        std::cout <<"POLARIZATION ERROR:" << polarization_error_ << "\t Valid:"<< individual.is_valid(instance) <<std::endl;

        if(polarization_error_best_individual > polarization_error_){
            guided_layer = layer;
            polarization_error_best_individual = polarization_error_;
        }
//        is
       // latex.save_instance_latex("teste2.tex",guided_layer);


    }

    std::cout <<"POLARIZATION ERROR BEST:" << polarization_error_best_individual << std::endl;


    RemoveTwoAndInsertOneLocalSearch localSearch;
//    RemoveLocalSearch localSearch;
    circuito.layer(&guided_layer);
    Layer layer_return = localSearch.localSearch(circuito,instance);
    circuito.layer(&layer_return);
    results = circuito.execute_circuit(instance);
    individual.set_layer(layer_return);
    double polarization_error_ = individual.calculate_polarization_error(instance,results);
    std::cout <<"POLARIZATION ERROR:" << polarization_error_ << std::endl;







}

